package cn.com.twoke.game.client;

import cn.com.twoke.game.client.cache.ClientCacheManager;
import cn.com.twoke.game.client.games.gomoku.entity.data.DropData;
import cn.com.twoke.game.client.handler.*;
import cn.com.twoke.game.common.constants.MessageType;
import cn.com.twoke.game.common.entity.message.*;
import cn.com.twoke.game.common.handler.MessageHandler;
import cn.com.twoke.game.common.utils.MessageUtil;

import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.*;

/**
 * @author 公众号：索码理(suncodernote)
 */
public class GameClientManager implements Runnable {


    public static final GameClientManager INSTANCE = new GameClientManager();

    static {
        INSTANCE.on(MessageType.CONNECT,new ConnectHandler());
        INSTANCE.on(MessageType.LOGIN, new LoginMessageHandler());
        INSTANCE.on(MessageType.LOGOUT, new LogoutMessageHandler());
        INSTANCE.on(MessageType.UPDATE_ONLINE_USER, new UpdateOnlineUserMessageHandler());
        INSTANCE.on(MessageType.INVITE_JOIN_GAME, new InviteJoinGameMessageHandler());
        INSTANCE.on(MessageType.START_GAME, new StartGameMessageHandler());
        INSTANCE.on(MessageType.GAME_CHAT, new GameChatMessageHandler());
        INSTANCE.on(MessageType.GAME_DATA, new GameDataMessageHandler());
        INSTANCE.on(MessageType.STOP_GAME, new StopGameMessageHandler());
    }

    private Selector selector;
    private SocketChannel socketChannel;
    private Map<Integer, MessageHandler<? super Message>> listeners;

    public GameClientManager() {
        try {
            selector = Selector.open();
            socketChannel = SocketChannel.open();
            socketChannel.configureBlocking(false);
            socketChannel.connect(new InetSocketAddress("localhost", 9999));
            socketChannel.register(selector, SelectionKey.OP_CONNECT);
            this.listeners = new HashMap<>();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public void on(MessageType messageType, MessageHandler listener) {
        System.out.println("registered: " + listener);
        this.listeners.put(messageType.getType(),listener);
    }

    @Override
    public void run() {
        try {
            while (true) {
                selector.select();
                Set<SelectionKey> selectedKeys = selector.selectedKeys();
                Iterator<SelectionKey> keyIterator = selectedKeys.iterator();

                while (keyIterator.hasNext()) {
                    SelectionKey key = keyIterator.next();

                    if (key.isConnectable()) {
                        SocketChannel client = (SocketChannel) key.channel();
                        if (client.isConnectionPending()) {
                            client.finishConnect();
                        }
                        MessageHandler<? super Message> handler = listeners.get(MessageType.CONNECT.getType());
                        if (handler != null) {
                            handler.handle(selector, client, null);
                        }
                        client.register(selector, SelectionKey.OP_READ);
                    } else if (key.isReadable()) {
                        SocketChannel client = (SocketChannel) key.channel();
                        Message message = MessageUtil.readMessage(client);
                        MessageHandler<? super Message> handler = listeners.get(message.getType().getType());
                        if (handler != null) {
                            handler.handle(selector, client, message);
                        }
                    }
                    keyIterator.remove();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void login(String username) {
        MessageUtil.writeMessage(socketChannel, new LoginMessage(username));
    }

    public void logout(String username) {
        MessageUtil.writeMessage(socketChannel, new LogoutMessage(username));
    }

    public void inviteJoinGame(String gameRoomId, String[] selectedPlayer,
                               String gameId,
                               String gameTitle) {
        MessageUtil.writeMessage(socketChannel, new InviteJoinGameMessage(gameRoomId, selectedPlayer,
                ClientCacheManager.INSTANCE.getUsername(), gameId, gameTitle));

    }

    public void dealInviteJoinGame(InviteJoinGameMessage message) {
        MessageUtil.writeMessage(socketChannel, message);

    }

    public void startGame(String roomMasterId, String roomId, String gameId, int playerCount) {
        MessageUtil.writeMessage(socketChannel, new StartGameMessage(roomMasterId, gameId, roomId, playerCount));
    }

    public void sendMessage(GameChatMessage message) {
        MessageUtil.writeMessage(socketChannel, message);
    }

    public void sendGameData(Object data, String id, String roomId) {
        MessageUtil.writeMessage(socketChannel, new GameDataMessage<>(data, id, roomId));
    }

    public void stopGame(String id, String roomId,String userId, boolean stopCurrentUser) {
        MessageUtil.writeMessage(socketChannel, new StopGameMessage(id, roomId, userId, stopCurrentUser));
    }
    public void stopGame(String id, String roomId,String userId) {
        MessageUtil.writeMessage(socketChannel, new StopGameMessage(id, roomId, userId, true));
    }
}